//	VirtualDub - Video processing and capture application
//	Graphics support library
//	Copyright (C) 1998-2007 Avery Lee
//
//	This program is free software; you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation; either version 2 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program; if not, write to the Free Software
//	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#include <vd2/system/math.h>
#include <vd2/Kasumi/region.h>
#include <vd2/Kasumi/text.h>

#include "defaultfont.inl"

void VDPixmapGetTextExtents(const VDOutlineFontInfo *font, float size, const char *pText, VDTextLayoutMetrics& out_Metrics) {
	if (!font)
		font = &g_VDDefaultFont_FontInfo;

	float invEmSquare = 1.0f / (float)font->mEmSquare;
	float scale = 1.0f / (255.0f * 65536.0f);
	float xscale = (float)(font->mMaxX - font->mMinX) * scale;
	float yscale = (float)(font->mMaxY - font->mMinY) * scale;

	float xinitstep = font->mMinX * 255.0f * scale;
	float yinitstep = -(font->mMaxY * scale + font->mDescent);

	float xoffset = xinitstep;
	float yoffset = yinitstep;

	vdrect32f bounds;
	bounds.invalidate();

	while(const char c = *pText++) {
		int index = (unsigned char)c - font->mStartGlyph;

		if ((unsigned)index >= (unsigned)(font->mEndGlyph - font->mStartGlyph))
			continue;

		const VDOutlineFontGlyphInfo& glyph = font->mpGlyphArray[index];
		const VDOutlineFontGlyphInfo& glyphNext = font->mpGlyphArray[index + 1];
		int nPoints = glyphNext.mPointArrayStart - glyph.mPointArrayStart;

		if (nPoints) {
			vdrect32 localBounds;
			localBounds.invalidate();

			const uint16 *pPoints = font->mpPointArray + glyph.mPointArrayStart;
			for(int i=0; i<nPoints; ++i) {
				uint16 pt = *pPoints++;

				localBounds.add(pt & 255, pt >> 8);
			}

			vdrect32f localBoundsF((float)localBounds.left, -(float)localBounds.bottom, (float)localBounds.right, -(float)localBounds.top);
			localBoundsF.scale(xscale, yscale);
			localBoundsF.translate(xoffset, yoffset);
			bounds.add(localBoundsF);
		}

		xoffset += glyph.mAWidth + glyph.mBWidth + glyph.mCWidth;
	}

	if (bounds.valid())
		bounds.scale(size * invEmSquare, size * invEmSquare);

	out_Metrics.mExtents = bounds;
	out_Metrics.mAdvance = (xoffset - xinitstep) * size * invEmSquare;
}

void VDPixmapConvertTextToPath(VDPixmapPathRasterizer& rast, const VDOutlineFontInfo *pFont, float size, float x, float y, const char *pText, const float transform[2][2]) {
	if (!pFont)
		pFont = &g_VDDefaultFont_FontInfo;

	vdfastvector<vdint2> points;

	float scale = size / ((float)pFont->mEmSquare * 255.0f * 65536.0f);
	float xscale = (float)(pFont->mMaxX - pFont->mMinX) * scale;
	float yscale = -(float)(pFont->mMaxY - pFont->mMinY) * scale;

	float xinitstep = pFont->mMinX * 255.0f * scale;
	float yinitstep = -pFont->mMaxY * scale - pFont->mDescent * size / (float)pFont->mEmSquare;

	static const float kIdentity[2][2]={1,0,0,1};

	if (!transform)
		transform = kIdentity;

	float xoffset = x + xinitstep * transform[0][0] + yinitstep * transform[0][1];
	float yoffset = y + xinitstep * transform[1][0] + yinitstep * transform[1][1];

	while(const char c = *pText++) {
		int index = (unsigned char)c - pFont->mStartGlyph;

		if ((unsigned)index >= (unsigned)(pFont->mEndGlyph - pFont->mStartGlyph))
			continue;

		const VDOutlineFontGlyphInfo& glyph = pFont->mpGlyphArray[index];
		const VDOutlineFontGlyphInfo& glyphNext = pFont->mpGlyphArray[index + 1];
		const uint16 *pPoints = pFont->mpPointArray + glyph.mPointArrayStart;
		const uint8 *pCommands = pFont->mpCommandArray + glyph.mCommandArrayStart;
		int nPoints = glyphNext.mPointArrayStart - glyph.mPointArrayStart;
		int nCommands = glyphNext.mCommandArrayStart - glyph.mCommandArrayStart;

		points.clear();
		points.resize(nPoints);

		for(int i=0; i<nPoints; ++i) {
			uint16 pt = *pPoints++;
			float fx1 = (pt & 255) * xscale;
			float fy1 = (pt >> 8) * yscale;
			points[i].set(VDRoundToInt(fx1*transform[0][0] + fy1*transform[0][1] + xoffset), VDRoundToInt(fx1*transform[1][0] + fy1*transform[1][1] + yoffset));
		}

		const vdint2 *srcpt = points.data();
		const vdint2 *startpt = points.data();

		while(nCommands--) {
			uint8 cmd = *pCommands++;
			int countm1 = (cmd & 0x7f) >> 2;

			for(int i=0; i<=countm1; ++i) {
				switch(cmd & 3) {
				case 2:
					rast.Line(srcpt[0], srcpt[1]);
					++srcpt;
					break;

				case 3:
					rast.QuadraticBezier(srcpt);
					srcpt += 2;
					break;
				}
			}

			if (cmd & 0x80) {
				rast.Line(*srcpt, *startpt);
				startpt = ++srcpt;
			}
		}

		float step = (glyph.mAWidth + glyph.mBWidth + glyph.mCWidth) * (size / (float)pFont->mEmSquare);
		xoffset += step * transform[0][0];
		yoffset += step * transform[1][0];
	}
}
